from common.CommonNode import CommonNode
from common.CommonHeap import CommonHeap
from common.Utils import Utils


class Node(CommonNode):
    def __init__(self, size, start, obj):
        super().__init__(size, start, obj)
        self.marked = False

    def mark(self):
        self.marked = True
        return self

    def unMark(self):
        self.marked = False
        return self

    def isMarked(self):
        return self.marked

    def clear(self):
        super().clear()
        self.unMark()


class Heap:
    def __init__(self, size):
        self.heapStart = Node(size, 0, None)
        self.size = size
        self.usedSize = 0
        self.chunk = 1
        self.root = []

    def firstFit(self, size):
        nd, addChunk = CommonHeap.firstFit(self.heapStart, size, Node)
        if addChunk:
            self.chunk += 1
        return nd

    def newObject(self, size, obj):
        node = self.firstFit(size)
        if node is not None:
            self.usedSize += size
            node.setObj(obj)
            return node
        else:
            print(self)
            raise Exception("分配失败")

    def freeObject(self, node):
        self.usedSize -= node.size
        decChunk = CommonHeap.freeObject(node)
        self.chunk -= decChunk

    def addRoot(self, node):
        self.root.append(node)
        return self

    def removeRoot(self, node):
        Utils.popIfExist(self.heapStart, node)

    def mark(self):
        CommonHeap.mark(self.root)

    def sweep(self):
        p = self.heapStart
        while p is not None:
            if not p.isFree() and not p.isMarked():
                p.unMark()
                self.freeObject(p)
            p = p.getNext()

    def gc(self):
        self.mark()
        self.sweep()

    def __str__(self):
        return f"total: {self.size}, used: {self.usedSize}, remained: {self.size-self.usedSize}, chunk: {self.chunk}"

    @staticmethod
    def reference(nodeA, nodeB):
        nodeA.addChild(nodeB)

    @staticmethod
    def unReference(nodeA, nodeB):
        nodeA.removeChild(nodeB)


if __name__ == '__main__':
    heap = Heap(1024)
    n0 = heap.newObject(10, "124")
    n1 = heap.newObject(10, "adcc")
    heap.addRoot(n1)
    heap.gc()
    print(heap)
